home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / Libraries / VideoToolbox 95.04.18 / Demos / Sandstorm.c < prev    next >
C/C++ Source or Header  |  1994-11-15  |  11KB  |  308 lines

  1. /*
  2. Sandstorm.c
  3. Copyright © 1989-1994 Denis Pelli
  4. This program shows a noise movie, a dynamic random checkerboard, at 66.7 Hz!
  5. The key routine, which shows each frame, is the VideoToolbox routine CopyBitsQuickly().
  6.  
  7. To get a true impression of white noise you need to compute lots of noise
  8. frames, so give it as much memory as you can, e.g. 3 MB. (Use the Finder Get
  9. Info command.) Sandstorm fills all the memory you give it with pre-computed
  10. noise, which does take some time. Each displayed frame is taken from a random
  11. offset within that noise.
  12.  
  13. Note: the amount of data that has to be transfered by CopyBitsQuickly() in each
  14. frame is proportional to window area and the bits/pixel of the display, as set by
  15. Control Panel Monitors. At 8 bits/pixel the maximum window that can be updated
  16. at 66 Hz is about 192x192. At 1 bit/pixel we can do at least 480x640.
  17.  
  18. Sandstorm--not CopyBitsQuickly--calls WaitNextEvent() before each
  19. frame, in order to be responsive to the mouse, and this results in occasional
  20. pauses as the Mac takes time out to do various chores.
  21.  
  22.  
  23. HISTORY:
  24. 11/23/88 dgp derived from truenoiseDemo2.c
  25. 4/7/89 dgp     I removed nearly all the hardware dependencies. The only remaining one
  26.             is the call to NewFieldTFB(). I don't know how to get rid of that, short
  27.             of writing a VBL task.
  28. 9/29/89 dgp I've nearly updated this to THINK C 4.0, but the call to TickCount, 
  29.             refers to the old profiler, and I don't have time to figure this out now.
  30. 10/28/89 dgp I replaced the call to NewFieldTFB() by a call to GDSetEntries() which
  31.             is a device-independent way to wait for the end of frame.
  32. 7/19/90 dgp Unfortunately the built-in video on the Mac IIci is buggy and doesn't
  33.             support the setEntries call.
  34. 10/17/90 dgp Yay. Finally removed last bugs! Replaced SlotToScreenDevice() by
  35.             AddressToScreenDevice() in order to make it compatible with built-in video
  36.             on Mac IIci, IIsi, and LC. Removed the setEntries call for compatibility
  37.             with Mac IIci built-in video.(Apple has acknowledged bug, but bug is
  38.             still present in System 6.07.) Fixed bug whereby resizing window on other
  39.             than the main screen left window blank until it was dragged again. 
  40.             Removed unused variables. Added zoom box.
  41. 10/18/90 dgp Tidied up. Now zooms onto screen with largest intersection, and zooms back
  42.             to original size. Uses as much memory as user allocates to program. 
  43.             Window now always confines itself to a single screen, but can be dragged
  44.             anywhere.
  45. 10/20/90 dgp Copied code from VideoTest to close window and quit on Command-W or
  46.             Command-. Prevented window title bar from being hidden behind the menu
  47.             bar.
  48. 7/22/91    dgp    Made compatible with MPW C. This required changing INT_MAX to SHRT_MAX.
  49.             However, performance is slow, since CopyBitsQuickly.c doesn't generate
  50.             hand-tuned assembly code when using MPW C.
  51. 8/6/91    dgp    Replaced randU() by RandFill(), which runs twice as fast.
  52. 8/24/91    dgp    Made compatible with THINK C 5.0.
  53. 7/20/92    dgp    tidied up the comments slightly. Confirmed compatibility with 32-bit
  54.             addressing.
  55. 8/27/92    dgp    replace SysEnvirons() by Gestalt()
  56. 1/13/93 dgp    changed defaults to maximize speed.
  57. 9/3/93    dgp    added call to ShieldCursor() for compatibility with nonstandard
  58.             video devices, e.g. Radius PowerView.
  59. 6/3/94    dgp    replaced low-memory global MBarHeight by GetMBarHeight().
  60. 9/5/94 dgp removed assumption in printf's that int==short.
  61. */
  62. #include "VideoToolbox.h"
  63. #if UNIVERSAL_HEADERS
  64.     #include <LowMem.h>
  65. #else
  66.     #define LMGetMBarHeight() (* (short *) 0x0BAA)
  67.     #define LMSetMBarHeight(MBarHeightValue) ((* (short *) 0x0BAA) = (MBarHeightValue))
  68. #endif
  69. void main(void);
  70. Boolean ZoomedOut(WindowPtr w);
  71. #define RAISE_PRIORITY    0    /* Optional. Contrary to Apple's rules,    */
  72.                             /* but speeds up the display. */
  73. #define SCROLL_BAR 15        /* Standard width of scroll bar */
  74. #define WAIT_NEXT_EVENT 0
  75.  
  76. void Sandstorm(void);
  77.  
  78. void main(void)
  79. {
  80.     Require(gestalt8BitQD);
  81.     Sandstorm();
  82. }
  83. void Sandstorm()
  84. {
  85.     register short *bufferPtr;
  86.     int i;
  87.     static char string[40];
  88.     static PixMap sand;
  89.     Rect r,unzoomedRect,gdRect;
  90.     GDHandle device;
  91.     WindowPtr window,aWindow,oldPort;
  92.     PixMap **myPixMapHandle;
  93.     static BitMap buffer;
  94.     long bufferBytes;
  95.     size_t sandBytes;
  96.     Boolean done=0,update;
  97.     long reSize;
  98.     int windowEvent=inDesk;
  99.     Boolean zoomedOut;
  100.     WStateData *wStateData;
  101.     RgnHandle ignoreRgn;
  102.     int pixelSize;
  103.     Point pt;
  104.     EventRecord event;
  105.     
  106.     /* INITIALIZE QuickDraw */
  107.     MaxApplZone();                        /* Expand heap to the limit. */
  108.     InitGraf(&qd.thePort);
  109.     InitFonts();
  110.     InitWindows();
  111.     InitCursor();
  112.     GetPort(&oldPort);
  113.     device=GetMainDevice();
  114.  
  115.     /* open a window on the device */
  116.     ignoreRgn=NewRgn();
  117.     SetRect(&r,0,0,192+SCROLL_BAR,192+SCROLL_BAR);
  118.     CenterRectInRect(&r,&(*device)->gdRect);
  119.     window=NewCWindow(NULL
  120.         ,&r,"\pNow computing noise ...",TRUE,zoomDocProc,(WindowPtr) -1L,TRUE,0L);
  121.     myPixMapHandle = ((CGrafPtr)window)->portPixMap;
  122.     MoveHHi((Handle) myPixMapHandle);
  123.     HLock((Handle) myPixMapHandle);
  124.  
  125.     /* Compute noise */
  126.     /* allocate buffer BitMap */
  127.     buffer.rowBytes=1024;
  128.     MaxApplZone();
  129.     bufferBytes = FreeMem();
  130.     bufferBytes-=100000L;    /* Grab most of available space. */
  131.     bufferBytes -= bufferBytes%buffer.rowBytes;
  132.     buffer.baseAddr=NULL;
  133.     for(;bufferBytes>0;bufferBytes -= buffer.rowBytes){
  134.         buffer.baseAddr = NewPtr(bufferBytes);
  135.         if (buffer.baseAddr!=NULL)break;
  136.     }
  137.     if(buffer.baseAddr==NULL)PrintfExit("\007Sorry, not enough memory for buffers.\n");
  138.     SetRect(&buffer.bounds,0,0,buffer.rowBytes*8L,bufferBytes/buffer.rowBytes);
  139.  
  140.     /* Fill buffer with noise. */
  141.     bufferPtr = (short *) buffer.baseAddr;
  142.     RandFill(buffer.baseAddr,bufferBytes);
  143.  
  144.     /* Show noise */
  145.     SetPort(window);
  146.     reSize=0;
  147.     while (1) {
  148.         wStateData=(*((WStateData **)((WindowPeek)window)->dataHandle));
  149.         unzoomedRect=wStateData->userState;
  150.         zoomedOut=ZoomedOut(window);
  151.         if(reSize){
  152.             SizeWindow(window,LoWord(reSize),HiWord(reSize),TRUE);
  153.             reSize=0L;
  154.         }
  155.         device=GetWindowDevice(window);
  156.         if(device==NULL){
  157.             done=1;
  158.             break;
  159.         }
  160.         r=window->portRect;
  161.         LocalToGlobalRect(&r);
  162.         gdRect=(*device)->gdRect;
  163.         /* leave room for window's title bar */
  164.         gdRect.top+=r.top-1-(*((WindowPeek)window)->strucRgn)->rgnBBox.top;
  165.         /* leave room for menu bar */
  166.         if(device==GetMainDevice())gdRect.top+=LMGetMBarHeight();
  167.         SectRect(&gdRect,&r,&r);
  168.         pixelSize=(**(**device).gdPMap).pixelSize;
  169.         i=r.left-(*device)->gdRect.left;
  170.         i=(i*pixelSize+16 & ~31)/pixelSize-i;    /* move to nearest 32-bit boundary */
  171.         OffsetRect(&r,i,0);                        /* Assumes window is >16 bits wide */
  172.         SectRect(&gdRect,&r,&r);
  173.         MoveWindow(window,r.left,r.top,TRUE);
  174.         OffsetRect(&r,-r.left,-r.top);
  175.         sand = **(*device)->gdPMap;    /* Initialize PixMap fields from screen */
  176.         sand.bounds=r;
  177.         sand.bounds.right  -=SCROLL_BAR;    /* Leave room for the scroll bars */
  178.         sand.bounds.bottom -=SCROLL_BAR;
  179.         sand.bounds.right=(sand.bounds.right*sand.pixelSize+14 & ~31)/sand.pixelSize;
  180.             /* round to multiple of 32 bits */
  181.         if(sand.bounds.right<32)sand.bounds.right=32;
  182.         sand.rowBytes = (sand.bounds.right*sand.pixelSize + 31 & ~31)/8;
  183.             /* round up to multiple of 32 bits (redundant) */
  184.         sandBytes = (size_t) sand.rowBytes * (size_t) sand.bounds.bottom;
  185.         if(bufferBytes/2 < sandBytes)
  186.         {
  187.             /* restrict height by amount of noise available */
  188.             sand.bounds.bottom=bufferBytes/sand.rowBytes/2;
  189.             sandBytes = (size_t) sand.rowBytes * (size_t) sand.bounds.bottom;
  190.         }    
  191.         sand.rowBytes |= 0x8000;    /* Mark it as a PixMap */
  192.         sand.pmVersion=0;
  193.         sand.packType=0;
  194.         sand.packSize=0;
  195.         sand.planeBytes=0;
  196.         sand.pmReserved=0;
  197.         SizeWindow(window
  198.             ,sand.bounds.right+SCROLL_BAR,sand.bounds.bottom+SCROLL_BAR,TRUE);
  199.         EraseRect(&window->portRect);
  200.         DrawGrowIcon(window);
  201.         if(zoomedOut && windowEvent!=inGrow && windowEvent!=inDrag){
  202.             wStateData=(*((WStateData **)((WindowPeek)window)->dataHandle));
  203.             r=window->portRect;
  204.             LocalToGlobalRect(&r);
  205.             r.left-=1;
  206.             r.right-=2;
  207.             wStateData->stdState=r;        
  208.             wStateData->userState=unzoomedRect;
  209.         }
  210.         sprintf(string,"%dx%dx%d bits"
  211.             ,(int)sand.bounds.right,(int)sand.bounds.bottom,(int)sand.pixelSize);
  212.         SetWTitle(window,c2pstr(string));
  213.         FlushEvents(everyEvent,0);
  214.         DiffRgn(GetGrayRgn(),((WindowPeek)window)->strucRgn,ignoreRgn);
  215.         while (1) {
  216.             update=0;            /* don't update window frame unless necessary */
  217.             #if RAISE_PRIORITY
  218.                 SetPriority(2);    /* Get more speed by suppressing keyboard, mouse, and ticks. */
  219.             #endif
  220.             sand.baseAddr = buffer.baseAddr;
  221.             /* choose grain that won't overflow short argument to nrand() */
  222.             i=(bufferBytes/SHRT_MAX+3)&~3;    /* round up to multiple of 4 */
  223.             sand.baseAddr += nrand((bufferBytes-sandBytes)/i)*(long)i;
  224.             if(((WindowPeek)window)->hilited){
  225.                 CopyBitsQuickly((BitMap *)&sand,(BitMap *)*myPixMapHandle
  226.                     ,&sand.bounds,&sand.bounds,srcCopy,NULL);
  227.                 // Notify nonstandard video devices that pixels have changed.
  228.                 pt.h=-(*myPixMapHandle)->bounds.left;
  229.                 pt.v=-(*myPixMapHandle)->bounds.top;
  230.                 ShieldCursor(&sand.bounds,pt);
  231.                 ShowCursor();
  232.             }
  233.             #if RAISE_PRIORITY
  234.                 SetPriority(0);    /* Revive keyboard and mouse. */
  235.             #endif
  236.             #if WAIT_NEXT_EVENT
  237.                if(WaitNextEvent(mDownMask+keyDownMask,&event,0,ignoreRgn)){
  238.                #else
  239.                if(GetNextEvent(mDownMask+keyDownMask,&event)){
  240.                #endif
  241.                 switch(event.what){
  242.                 case keyDown:
  243.                     if(event.modifiers & cmdKey) switch(event.message & charCodeMask) {
  244.                         case '.':
  245.                         case 'w':
  246.                         done=1;
  247.                     }
  248.                     break;
  249.                 case mouseDown:
  250.                     update=1;
  251.                     windowEvent=FindWindow(event.where,&aWindow);
  252.                     if(aWindow==window){
  253.                         switch(windowEvent){
  254.                         case inDrag:
  255.                             DragWindow(window,event.where,&qd.screenBits.bounds);
  256.                             break;
  257.                         case inGoAway:
  258.                             done=TrackGoAway(window,event.where);
  259.                             break;
  260.                         case inGrow:
  261.                             r.top=r.left=32+SCROLL_BAR;    /* minimum size */
  262.                             r.bottom=r.right=1024+SCROLL_BAR;    /* max size */
  263.                             reSize = GrowWindow(window,event.where,&r);
  264.                             break;
  265.                         case inZoomIn:
  266.                         case inZoomOut:
  267.                             Zoom(window,windowEvent,&event);
  268.                             break;
  269.                         case inContent:
  270.                             break;
  271.                         default:
  272.                             update=0;
  273.                             break;
  274.                         }
  275.                         break;
  276.                     }
  277.                     break;
  278.                 }
  279.             }            
  280.             if(update || done)break;
  281.         }
  282.         if(done)break;
  283.     }
  284.     SetPort(oldPort);
  285.     DisposeRgn(ignoreRgn);
  286.     DisposPtr(buffer.baseAddr);
  287.     DisposeWindow(window);
  288. }
  289.  
  290. Boolean ZoomedOut(WindowPtr w)
  291. /* Determine whether window is "standard" size, i.e. zoomed out. */
  292. {
  293.     Point pt;
  294.     Rect r,myRect;
  295.     Boolean zoomedOut;
  296.     
  297.     myRect=(*((WStateData **)((WindowPeek)w)->dataHandle))->stdState;
  298.     pt.h=0;
  299.     pt.v=0;
  300.     LocalToGlobal(&pt);
  301.     r = w->portRect;
  302.     OffsetRect(&r,pt.h,pt.v);
  303.     zoomedOut=r.top==myRect.top
  304.         && r.left==myRect.left
  305.         && r.bottom==myRect.bottom
  306.         && r.right==myRect.right;
  307.     return zoomedOut;
  308. }